package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.IdAndNumDTO;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.trade.OrderBasicDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningPlanDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author xiaohai
 * @since 2024-09-11
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {

    private final CourseClient courseClient;

    private final CatalogueClient catalogueClient;

    // 会导致循环依赖
    //private final ILearningRecordService recordService;
    private final LearningRecordMapper recordMapper;

    /**
     * 添加课程到课表
     *
     * @param dto
     */
    @Override
    public void addLesson(OrderBasicDTO dto) {
        // 1.远程调用tj-course微服务，根据课程id查询出课程信息(课程有效期)
        List<CourseSimpleInfoDTO> courseList = courseClient.getSimpleInfoList(dto.getCourseIds());
        if (CollUtils.isEmpty(courseList)) {
            throw new DbException("课程数据不存在");
        }
        // 唯一标识  订单id==>redis
        // 判断redis里面是否有当前订单id,如果有，就不在调用业务

        // 2.遍历课程信息,封装到LearningLesson对象(课程id，用户id，过期时间),放到List<LearningLesson>
        List<LearningLesson> lessonList = new ArrayList<>();
        for (CourseSimpleInfoDTO course : courseList) {
            LearningLesson lesson = new LearningLesson();
            lesson.setUserId(dto.getUserId());
            lesson.setCourseId(course.getId());
            lesson.setExpireTime(LocalDateTime.now().plusMonths(course.getValidDuration()));

            lessonList.add(lesson);
        }
        // 3.批量保存到数据库
        saveBatch(lessonList);

        // 把订单id存到redis里面去，保存60s
    }

    /**
     * 根据id分页查询课表
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<LearningLessonVO> queryMyLessons(PageQuery query) {
        // 1.分页查询出当前用户的课表信息(获取当前用户id)
        Long userId = UserContext.getUser();

        Page<LearningLesson> page = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<LearningLesson> lessonList = page.getRecords();
        if (CollUtils.isEmpty(lessonList)) {
            return PageDTO.empty(page);
        }
        // 2.根据courseId查询出当前课程
        List<Long> courseIds = lessonList
                .stream()
                .map(LearningLesson::getCourseId)
                .collect(Collectors.toList());
        List<CourseSimpleInfoDTO> courseList = courseClient.getSimpleInfoList(courseIds);
        if (CollUtils.isEmpty(courseList)) {
            throw new DbException("课程信息不存在");
        }

        // courseList转换为map,key是课程id，value就是课程对象
        Map<Long, CourseSimpleInfoDTO> courseMap = courseList
                .stream()
                .collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));

        // 3.遍历课表List,封装LearningLessonVo
        List<LearningLessonVO> voList = new ArrayList<>();
        for (LearningLesson lesson : lessonList) {
            LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);

            // 封装课程数据
            CourseSimpleInfoDTO course = courseMap.get(lesson.getCourseId());
            if (course != null) {
                vo.setCourseName(course.getName());
                vo.setCourseCoverUrl(course.getCoverUrl());
                vo.setSections(course.getSectionNum());
            }
            voList.add(vo);
        }

        // 4.封装pageDTO
        return PageDTO.of(page, voList);
    }

    /**
     * 查询当前用户最近学习的课程
     *
     * @return
     */
    @Override
    public LearningLessonVO queryCurrent() {
        // 1.查询最近学习的课程(一门)
        // select * from learning_lesson where user_id = 2 and status = 1 order by latest_learn_time desc limit 1;
        Long userId = UserContext.getUser();
        LearningLesson lesson = getBaseMapper().queryCurrent(userId);
        if (lesson == null) {
            return null;
        }
        LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);

        // 2.根据课程id查询课程信息(远程调用)
        CourseFullInfoDTO course = courseClient
                .getCourseInfoById(lesson.getCourseId(), false, false);
        if (course == null) {
            throw new DbException("课程数据不存在");
        }
        vo.setCourseName(course.getName());
        vo.setCourseCoverUrl(course.getCoverUrl());
        vo.setSections(course.getSectionNum());

        // 3.统计课表中当前用户课程数量
        // select count(*) from learning_lesson where user_id = 2;
        Integer countAmount = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .count();
        vo.setCourseAmount(countAmount);

        // 4.根据最近一次学习的小节id查询出小节信息(远程调用)
        /*List<Long> ids = new ArrayList<>();
        ids.add(lesson.getLatestSectionId());*/
        Long latestSectionId = lesson.getLatestSectionId();
        if (latestSectionId != null && latestSectionId != 0) {
            List<CataSimpleInfoDTO> cataList = catalogueClient
                    .batchQueryCatalogue(List.of(lesson.getLatestSectionId()));
            if (CollUtils.isNotEmpty(cataList)) {
                CataSimpleInfoDTO cata = cataList.get(0);
                if (cata != null) {
                    vo.setLatestSectionName(cata.getName());
                    vo.setLatestSectionIndex(cata.getCIndex());
                }
            }
        }
        return vo;
    }

    /**
     * 根据课程id查询课程信息
     *
     * @param courseId
     * @return
     */
    @Override
    public LearningLessonVO queryByCourseId(Long courseId) {
        // 1.根据用户id和课程id查询出课表LearningLesson
        Long userId = UserContext.getUser();
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getCourseId, courseId)
                .eq(LearningLesson::getUserId, userId)
                .one();
        if (lesson == null) {
            return null;
        }
        // 2.根据课程id查询出课程信息
        CourseFullInfoDTO course = courseClient
                .getCourseInfoById(lesson.getCourseId(), false, false);
        if (course == null) {
            throw new DbException("课程信息不存在");
        }
        // 3.封装VO
        LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
        vo.setCourseName(course.getName());
        vo.setCourseCoverUrl(course.getCoverUrl());
        vo.setSections(course.getSectionNum());

        return vo;
    }

    /**
     * 根据课程id查询课程状态
     *
     * @param courseId
     * @return
     */
    @Override
    public Long isLessonValid(Long courseId) {
        Long userId = UserContext.getUser();
        if (userId == null) {
            return null;
        }
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                // .eq(LearningLesson::getStatus, LessonStatus.LEARNING)
                .one();
        if (lesson == null) {
            return null;
        }
        return lesson.getId();
    }

    /**
     * 创建我的学习计划
     *
     * @param dto
     */
    @Override
    public void createLessonPlan(LearningPlanDTO dto) {
        // 1.根据userId和courseId查询出课表信息
        Long userId = UserContext.getUser();
        LearningLesson lesson = lambdaQuery()
                .eq(LearningLesson::getCourseId, dto.getCourseId())
                .eq(LearningLesson::getUserId, userId)
                .one();
        if (lesson == null) {
            throw new DbException("课表信息不存在");
        }
        // 2.更新weekFraq,plan_status
        //lesson.setWeekFreq(dto.getFreq());
        //updateById(lesson);
        LearningLesson learningLesson = new LearningLesson();
        learningLesson.setWeekFreq(dto.getFreq());
        learningLesson.setId(lesson.getId());
        if (lesson.getPlanStatus() == PlanStatus.NO_PLAN) {
            learningLesson.setPlanStatus(PlanStatus.PLAN_RUNNING);
        }
        updateById(learningLesson);
    }

    /**
     * 查询我的学习计划
     *
     * @param pageQuery
     * @return
     */
    @Override
    public LearningPlanPageVO queryMyPlan(PageQuery pageQuery) {
        LearningPlanPageVO vo = new LearningPlanPageVO();
        // 1.获得本周的开始和结束时间
        LocalDateTime weekBeginTime = DateUtils.getWeekBeginTime(LocalDate.now());
        LocalDateTime weekEndTime = DateUtils.getWeekEndTime(LocalDate.now());
        // 2.获取用户id
        Long userId = UserContext.getUser();
        // 3.查询当前用户本周计划统计
        // 3.1 查询当前用户本周已经学习小节总数 学习记录表 select count(*) from learning_record where user_id = 2 and finish_time > '2021-10-10 00:00:00' and finish_time < '2023-10-10 23:00:00' and finished = 1;
        Integer weekFinished = recordMapper.selectCount(
                new LambdaQueryWrapper<LearningRecord>()
                        .eq(LearningRecord::getFinished, true)
                        .gt(LearningRecord::getFinishTime, weekBeginTime)
                        .lt(LearningRecord::getFinishTime, weekEndTime)
                        .eq(LearningRecord::getUserId, userId)
        );
        vo.setWeekFinished(weekFinished);
        // 3.2 查询当前用户本周计划学习小节总数
        Integer weekTotalPlan = getBaseMapper().queryWeekTotalPlan(userId);
        vo.setWeekTotalPlan(weekTotalPlan);
        // 4.查询当前用户列表数据(分页)
        // 4.1 分页查询当前用户的课表 select * from learning_lesson where user_id = 2 and plan_status = 1 and status in (0,1) order by learning_lesson.latest_learn_time limit 0, 10;
        Page<LearningLesson> page = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
                .in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
                .page(pageQuery.toMpPage("latest_learn_time", false));

        List<LearningLesson> lessonList = page.getRecords();
        if (CollUtils.isEmpty(lessonList)) {
            return vo.emptyPage(page);
        }
        // 4.2 根据courseId查询课程信息
        List<Long> courseIds = lessonList.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
        List<CourseSimpleInfoDTO> courseList = courseClient.getSimpleInfoList(courseIds);
        if (CollUtils.isEmpty(courseList)) {
            throw new DbException("课程信息不存在");
        }
        Map<Long, CourseSimpleInfoDTO> courseMap = courseList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, CourseSimpleInfoDTO -> CourseSimpleInfoDTO));
        // 4.3 查询某个课程本周的学习小节 select lesson_id,count(*) from learning_record where user_id = 2 and finished = 1 and finish_time > '2021-10-10 00:00:00' and finish_time < '2023-10-10 23:00:00'group by lesson_id;
        List<IdAndNumDTO> idAndNumDTOList = recordMapper.countLearnedSections(userId, weekBeginTime, weekEndTime);
        Map<Long, Integer> idAndNumMap = IdAndNumDTO.toMap(idAndNumDTOList);

        // 4.4 遍历课表list,封装成VoList
        List<LearningPlanVO> volist = new ArrayList<>();
        for (LearningLesson lesson : lessonList) {
            // 每遍历一次都要封装成一个LearningPlanVO
            LearningPlanVO planVO = BeanUtils.copyBean(lesson, LearningPlanVO.class);
            // 封装课程信息
            CourseSimpleInfoDTO course = courseMap.get(lesson.getCourseId());
            if (course != null) {
                planVO.setCourseName(course.getName());
                planVO.setSections(course.getSectionNum());
            }
            // 封装已经学习的小节数据
            planVO.setWeekLearnedSections(idAndNumMap.getOrDefault(lesson.getId(), 0));
            volist.add(planVO);
        }
        return vo.pageInfo(page.getTotal(), page.getPages(), volist);
    }

    @PostConstruct
    public void initMethod() {
        // 初始化
        // 执行我们的逻辑方法，需要自动调用
        log.info("我被Spring创建了");
    }

    @PreDestroy
    public void destroyMethod() {
        // 销毁 ourBean对象
        log.info("我被Spring销毁了");
    }
}
